<template>
	<template v-if="linkOnly">
		<a
			:class="[
				'app-editor-container',
				'app-data-picker',
				`app-data-picker-${name}`,
			]"
			@click="openLinkView"
		>
			{{ value }}
		</a>
	</template>
	<template v-else-if="isAC && !isDropdown">
		<a-auto-complete
			:class="[
				'app-editor-container',
				'app-data-picker',
				`app-data-picker-${name}`,
			]"
			ref="autoComRef"
			:value="currentVal"
			:options="items"
			:open="open"
			:disabled="disabled || readonly"
			dropdownClassName="app-editor-data-picker-dropdown"
			@dropdownVisibleChange="handleVisibleChange"
			@search="onSearch"
			@focus="onFocus"
			@blur="onBlur"
		>
			<template #option="option">
				<a-empty v-if="option.noData" :image="simpleImage" />
				<div v-else @click="onSelect(option[deKeyField])">
					{{ option[deMajorField] }}
				</div>
			</template>
			<a-input :placeholder="placeholder">
				<template #suffix>
					<CloseCircleOutlined
						v-show="value"
						class="suffix-icon"
						@click="clear"
					/>
					<DownOutlined v-show="!open" class="suffix-icon" />
					<UpOutlined v-show="open" class="suffix-icon" />
					<SearchOutlined
						v-if="showPickUpView && showButton"
						class="suffix-icon"
						@click="openView"
					/>
					<ExportOutlined
						v-if="showLinkView"
						class="suffix-icon"
						@click="openLinkView"
					/>
				</template>
			</a-input>
		</a-auto-complete>
	</template>
	<template v-else-if="!isAC">
		<a-input
			:class="[
				'app-editor-container',
				'app-data-picker',
				`app-data-picker-${name}`,
			]"
			:value="value"
			:placeholder="placeholder"
			@focus="($event:any)=>{onFocusBlurEmit('focus',$event)}"
			@blur="($event:any)=>{onFocusBlurEmit('blur',$event)}"
		>
			<template #suffix>
				<CloseCircleOutlined
					v-show="value"
					class="suffix-icon"
					@click="clear"
				/>
				<SearchOutlined
					v-if="showPickUpView && showButton"
					class="certain-category-icon"
					@click="openView"
				/>
				<LinkOutlined v-if="showLinkView" @click="openLinkView" />
			</template>
		</a-input>
	</template>
	<template v-else-if="isDropdown">
		<a-select
			ref="dataPicker"
			:class="[
				'app-editor-container',
				'app-data-picker',
				`app-data-picker-${name}`,
			]"
			showArrow
			:showSearch="false"
			:mode="multiple ? 'multiple' : 'tag'"
			:value="currentVal"
			:disabled="disabled"
			:filterOption="false"
			@change="onChange"
			@focus="onFocus"
			@blur="onBlur"
			@dropdownVisibleChange="handleVisibleChange"
			:placeholder="placeholder"
		>
			<template #suffixIcon>
				<span class="app-data-picker-dropdown-select-icon">
					<CloseCircleOutlined
						v-show="value"
						class="suffix-icon"
						@click="clear"
					/>
					<SearchOutlined
						v-if="showPickUpView && showButton"
						class="certain-category-icon"
						@click="openView"
					/>
					<LinkOutlined v-if="showLinkView" @click="openLinkView" />
				</span>
			</template>
			<a-select-option
				v-for="(item, index) in items"
				:key="index"
				:value="item[deKeyField]"
				:label="item[deMajorField]"
				:title="item[deMajorField]"
			>
				{{ item[deMajorField] }}
			</a-select-option>
			<template #tagRender="{ closable, onClose, option }">
				<a-tag
					:closable="closable"
					style="margin-right: 3px"
					@close="onClose"
					:title="option?.label"
				>
					{{ option?.label }}
				</a-tag>
			</template>
		</a-select>
	</template>
</template>

<script setup lang="ts">
import { Ref, ref } from 'vue';
import { Empty } from 'ant-design-vue';
import {
	SearchOutlined,
	ExportOutlined,
	CloseCircleOutlined,
	DownOutlined,
	UpOutlined,
	LinkOutlined,
} from '@ant-design/icons-vue';
import { IParam, IEvent, computedNavData } from '@/core';
import { dataPickerProps } from './data-picker';
import {
	handleEditorNavParams,
	useEditorTypeParams,
	searchEntityData,
} from '@/hooks/use-editor';
import { deepCopy, isExistAndNotEmpty } from '@/core/utils';
// 外部数据选择编辑器（一般应用外键数据的录入），支持AC或数据选择的方式进行录入，数据选择编辑器需要额外的值项属性存储实际的值，自身只存储显示内容。
// 数据选择编辑器提供多种形式，有能输入能选择、只能输入不能选择的或是只能选择的，另外为方便快速查看引用的数据，还提供了数据链接功能，可直接打开引用数据的相关视图(单选)
// 邮件地址输入控件，一般应用于类似邮件地址输入场景，用户可直接输入（提供AC支持）或是从外部数据中选择输入（多选）
interface EditorEmit {
	(name: 'component-action', value: IEvent<string>): void;
}
const props = defineProps(dataPickerProps);
const emit = defineEmits<EditorEmit>();
const { navContext, navViewParam } = handleEditorNavParams(props);
/**
 * 下拉数据集
 */
let items: Ref<any[]> = ref([]);
/**
 * 搜索值
 */
let searchVal: any = ref(undefined);
/**
 * 搜索状态
 */
let isSearch = ref(false);
/**
 * 下拉展开状态
 */
let open = ref(false);
/**
 * dataPicker引用
 */
const dataPicker: any = ref(null);
const simpleImage = Empty.PRESENTED_IMAGE_SIMPLE;
/**
 * 数据类型校验
 */
const {
	validateConfig,
	valueType,
	valueSeparator,
	objectNameField,
	objectIdField,
	objectValueField,
} = useEditorTypeParams();
validateConfig();
const compAttrs: IParam = useAttrs();
const autoComRef = ref();
let selects: IParam[] = [];

/**
 * 显示选择视图
 */
const showPickUpView = computed(() => {
	return compAttrs.PICKUPVIEW == 'TRUE';
});

/**
 * 显示连接视图
 */
const showLinkView = computed(() => {
	return compAttrs.LINKVIEW == 'TRUE';
});

/**
 * 当前值
 */
let currentVal: Ref<any> = computed(() => {
	let curValue: any;
	selects = [];
	try {
		if (props.value) {
			if (props.multiple) {
				curValue = [];
				if (valueType == 'OBJECTS') {
					(props.value as any[]).forEach((item: any) => {
						selects.push({
							[props.deKeyField]: item[objectIdField as string],
							[props.deMajorField]: item[objectNameField as string],
						});
					});
				} else {
					if (objectIdField) {
						let values = (props.value as string).split(
							valueSeparator ? valueSeparator : ','
						);
						values.forEach((value: string) => {
							selects.push({
								[props.deKeyField]: value,
							});
						});
					} else {
						selects = JSON.parse(props.value as string);
					}
				}
				selects.forEach((select: IParam) => {
					curValue.push(select[props.deKeyField]);
				});
			} else {
				if (valueType == 'OBJECT') {
					selects.push({
						[props.deKeyField]: props.data[props.valueItem],
						[props.deMajorField]: (props.value as any)[
							objectNameField as string
						],
					});
				} else {
					selects.push({
						[props.deKeyField]: props.data[props.valueItem],
						[props.deMajorField]: props.value,
					});
				}
				if (isSearch.value) {
					curValue = searchVal.value;
				} else {
					curValue = selects[0][props.deMajorField];
				}
			}
			selects.forEach((select: IParam) => {
				const item = items.value.find((item: IParam) =>
					Object.is(select[props.deKeyField], item[props.deKeyField])
				);
				if (!item && select[props.deKeyField]) {
					items.value.push(select);
				}
			});
		}
	} catch (error) {
		console.log(error);
	}
	return curValue;
});

/**
 * @description 填充外键值附加数据
 * @param item 选中数据
 */
const fillPickUpData = (item: IParam) => {
	if (props.pickUpData) {
		let pickUpDataArray: string[] = props.pickUpData.split(';');
		if (pickUpDataArray && pickUpDataArray.length > 0) {
			for (let i = 0; i < pickUpDataArray.length; i++) {
				if (item) {
					emit('component-action', {
						name: pickUpDataArray[i],
						action: 'valueChange',
						data: item[pickUpDataArray[i]],
					});
				} else {
					emit('component-action', {
						name: pickUpDataArray[i],
						action: 'valueChange',
						data: null,
					});
				}
			}
		}
	}
};

/**
 * @description 失去焦点
 */
const onBlur = ($event: any) => {
	if (!props.multiple) {
		searchVal.value = '';
		isSearch.value = false;
		open.value = false;
	}
	onFocusBlurEmit('blur', $event);
};

/**
 * @description 聚焦
 */
const onFocus = ($event: any) => {
	if (!isSearch.value) {
		searchVal.value = '';
		isSearch.value = true;
		open.value = true;
	}
	onFocusBlurEmit('focus', $event);
};

/**
 * @description 处理下拉显示改变
 * @param open 打开状态
 */
const handleVisibleChange = (open: boolean) => {
	if (open) {
		onSearch('');
	}
};

/**
 * @description 自动填充搜索
 * @param value 搜索值
 */
const onSearch = (value: string) => {
	searchVal.value = value;
	let _navContext = deepCopy(navContext);
	let _navViewParam = deepCopy(navViewParam);
	const _data = computedNavData(
		props.data,
		_navContext,
		_navViewParam,
		props.localParam
	);
	Object.assign(_navViewParam, _data, { query: searchVal.value, size: 1000 });
	if (props.sort) {
		Object.assign(_navViewParam, { sort: props.sort });
	}
	let requestException: string = App.ts(
		'common.generic.requestexception',
		'请求异常'
	);
	if (!props.acParams) {
		console.warn(App.ts('common.generic.miss', '参数不存在'));
	} else {
		const { serviceName, interfaceName } = props.acParams;
		const { deKeyField, deCodeName } = props;
		searchEntityData(
			serviceName,
			interfaceName,
			_navContext,
			_navViewParam,
			deKeyField,
			deCodeName
		)
			.then((response: any) => {
				if (!response) {
					console.warn(App.ts('common.generic.loadfail', '加载数据失败'));
					return;
				} else {
					if (props.isAC && !props.isDropdown && response.length == 0) {
						items.value = [{ noData: true }];
					} else {
						items.value = [...response];
					}
				}
			})
			.catch((error: any) => {
				if (props.isAC && !props.isDropdown) {
					items.value = [{ noData: true }];
				} else {
					items.value = [];
				}
				console.warn(error && error.message ? error.message : requestException);
			});
	}
};

/**
 * @description 自动填充选中
 * @param select 选中数据
 */
const onSelect = (select: any) => {
	const selectItem = items.value.find((item: IParam) =>
		Object.is(item[props.deKeyField], select)
	);
	switchAppAc();
	isSearch.value = false;
	autoComRef.value.blur();
	searchVal.value = '';
	let value: any = null;
	let valueItem: any = null;
	if (selectItem) {
		if (valueType == 'OBJECT') {
			value = handleObjectParams(selectItem);
		} else {
			value = selectItem[props.deMajorField];
		}
		valueItem = selectItem[props.deKeyField];
	}
	emit('component-action', {
		name: `${props.name}`,
		action: 'valueChange',
		data: value,
	});
	if (props.valueItem) {
		emit('component-action', {
			name: props.valueItem,
			action: 'valueChange',
			data: valueItem,
		});
	}
	fillPickUpData(selectItem);
};

/**
 * @description 处理值改变
 * @param selects 选中数据
 */
const onChange = (selects: any, dateString: any) => {
	isSearch.value = false;
	const data: IParam[] = [];
	if (props.multiple) {
		selects.forEach((value: string) => {
			const select = items.value.find((_item: IParam) =>
				Object.is(_item[props.deKeyField], value)
			);
			if (select) {
				data.push(select);
			}
		});
	} else {
		let select = items.value.find((_item: IParam) => {
			return Object.is(_item[props.deKeyField], selects);
		});
		data.push(select);
	}
	handleEditorEmit(data);
};

/**
 * @description 处理对象类型参数
 * @param select 选中数据
 */
const handleObjectParams = (select: IParam): IParam => {
	const object: IParam = {};
	if (objectNameField) {
		Object.assign(object, {
			[objectNameField]: select[props.deMajorField],
		});
	}
	if (objectIdField) {
		Object.assign(object, {
			[objectIdField]: select[props.deKeyField],
		});
	}
	if (objectValueField) {
		Object.assign(object, {
			[objectValueField]: deepCopy(select),
		});
	}
	return object;
};

/**
 * @description 切换下拉显示
 */
const switchAppAc = () => {
	open.value = !open.value;
};

/**
 * @description 清空
 */
const clear = (event: any) => {
	event.stopPropagation();
	event.preventDefault();
	if (props.valueItem) {
		emit('component-action', {
			name: props.valueItem,
			action: 'valueChange',
			data: null,
		});
	}
	emit('component-action', {
		name: `${props.name}`,
		action: 'valueChange',
		data: null,
	});
};

/**
 * @description 处理pickupView值改变
 * @param data 选中数据
 */
const handlePickUpViewValueChange = (data: IParam[]): any => {
	const result = data.map((item: IParam) => {
		return item.$DO || item;
	});
	handleEditorEmit(result);
	if (dataPicker.value) {
		dataPicker.value.focus();
		dataPicker.value.blur();
	}
};

/**
 * @description 处理编辑器抛值
 * @param data 选中数据
 */
const handleEditorEmit = (data: IParam[]) => {
	let value: any = null;
	if (props.multiple) {
		let selects: any[] = [];
		data.forEach((item: any, i: number) => {
			const index = items.value.findIndex((_item: any) =>
				Object.is(item[props.deKeyField], _item[props.deKeyField])
			);
			if (index < 0) {
				items.value.push(item);
			}
			let selected: any;
			if (valueType == 'OBJECTS') {
				selected = handleObjectParams(item);
			} else {
				// SIMPLE (有objectIdField的情况为搜索表单使用时特殊情况)
				if (objectIdField) {
					selected = item[props.deKeyField];
				} else {
					selected = {
						[props.deMajorField]: item[props.deMajorField],
						[props.deKeyField]: item[props.deKeyField],
					};
				}
			}
			selects.push(selected);
		});
		if (selects.length > 0) {
			if (valueType == 'OBJECTS') {
				value = selects;
			} else {
				value = objectIdField
					? selects.join(valueSeparator ? valueSeparator : ',')
					: JSON.stringify(selects);
			}
		} else {
			value = null;
		}
		emit('component-action', {
			name: `${props.name}`,
			action: 'valueChange',
			data: value,
		});
	} else {
		let valueItem: any = null;
		const item = data[0];
		if (item) {
			if (valueType == 'OBJECT') {
				value = handleObjectParams(item);
			} else {
				value = item[props.deMajorField];
			}
			valueItem = item[props.deKeyField];
		}
		if (props.valueItem) {
			emit('component-action', {
				name: props.valueItem,
				action: 'valueChange',
				data: valueItem,
			});
		}
		emit('component-action', {
			name: `${props.name}`,
			action: 'valueChange',
			data: value,
		});
	}
};

/**
 * @description 打开链接视图
 */
const openLinkView = (event: any): void => {
	event.preventDefault();
	event.stopPropagation();
	if (
		!props.data ||
		!props.valueItem ||
		!props.data.hasOwnProperty(props.valueItem)
	) {
		const formdataexception = App.ts(
			'common.datapicker.formdataexception',
			'表单数据异常！'
		);
		const valueitemexception = App.ts(
			'common.datapicker.valueitemexception',
			'值项异常'
		);
		if (!props.data) {
			console.error(formdataexception);
		} else {
			console.error(valueitemexception);
		}
		return;
	}
	if (!props.linkView) {
		App.getNotificationHelper().error(
			App.ts('common.generic.error'),
			App.ts('common.datapicker.nolinkview')
		);
		return;
	}
	// 公共参数处理
	let data: any = {
		param: {},
		context: {},
	};
	Object.assign(data.param, navViewParam);
	Object.assign(data.context, navContext);

	// 参数处理
	let _context = data.context;
	let _param = data.param;
	if (props.data[props.valueItem]) {
		Object.assign(_context, {
			[props.deKeyField]: props.data[props.valueItem],
		});
	}
	const view = App.getAppViewConfig()?.[props.linkView];
	App.getOpenViewHelper().openPage(view, _context, _param);
};

/**
 * @description 打开选择视图
 */
const openView = async (event: any) => {
	event.preventDefault();
	event.stopPropagation();
	if (props.disabled) {
		return;
	}
	if (!props.pickUpView) {
		App.getNotificationHelper().error(
			App.ts('common.generic.error'),
			App.ts('common.datapicker.nopickupview')
		);
		return;
	}
	const view = App.getAppViewConfig()?.[props.pickUpView];
	if (!view) {
		return;
	}
	const params: IParam = {};
	let context = deepCopy(navContext);
	const viewParams = deepCopy(navViewParam);
	let srfselecteddata: IParam[] = [];
	if (selects && selects.length > 0) {
		selects.forEach((item: IParam) => {
			srfselecteddata.push({
				srfkey: item[props.deKeyField],
				srfmajortext: item[props.deMajorField],
			});
		});
	}
	if (srfselecteddata && srfselecteddata.length > 0) {
		Object.assign(viewParams, { srfselecteddata: srfselecteddata });
	}
	if (
		!Object.is(view.openMode, 'POPOVER') &&
		!Object.is(view.openMode, 'DRAWER')
	) {
		Object.assign(params, { openMode: 'POPUPMODAL' });
	}
	const tempViewParam = computedNavData(
		props.data,
		context,
		viewParams,
		props.localParam
	);
	Object.assign(viewParams, tempViewParam);
	const result = await App.getOpenViewHelper().openModal(
		view,
		context,
		viewParams
	);
	if (result && result.ok) {
		handlePickUpViewValueChange(result.data as Array<any>);
	}
};

/**
 * 抛出聚焦,失去焦点事件
 */
const onFocusBlurEmit = (type: 'blur' | 'focus', $event: any) => {
	if (type == 'blur') {
		emit('component-action', {
			name: `${props.name}`,
			action: 'editorBlur',
			data: $event,
		});
	} else if (type == 'focus') {
		emit('component-action', {
			name: `${props.name}`,
			action: 'editorFocus',
			data: $event,
		});
	}
};
</script>
